#if 1
#include "IPCAM_Export.h"
#include "Daemon_UpgradeByNet.h"
#include "Daemon.h"
#include "Daemon_Common.h"
#include "Daemon_Init.h"

#ifndef __HuaweiLite__
#include "Daemon_BackupRecover.h"
#include <sys/reboot.h>
#include <SDcard.h>
#else
#include "Upgrade.h"
#include "System.h"
#include "Net.h"
#define     SIZEOFNETMSGPACK             (sizeof(NETMSGPACKET))  
#endif /* __HuaweiLite__ */


char Upgrade_now = 0;//升级标志


typedef struct {
    char            bUpgrading;
    NETMSGPACKET	sp;
    int             fd;
}DaemonUpgradeContext;

static DaemonUpgradeContext g_daemonUpgradeCtx = {
    .bUpgrading = 0,
    .sp         = {0},
    .fd         = -1,
};

static inline DaemonUpgradeContext *daemon_upgrade_GetCtx(void)
{
    return &g_daemonUpgradeCtx;
}

static INT NetSendPacketVa(INT fd, UCHAR *buf, INT size, ULONG sec, ULONG usec)
{
	fd_set ww_set;
	struct timeval tv;
	int ret;
	if (fd < 0)
	{
		return -1;
	}
	   
	FD_ZERO(&ww_set);
	FD_SET(fd, &ww_set);
	tv.tv_sec =	TIMEOUT_SEC; 
	tv.tv_usec= TIMEOUT_USEC;
	if ((ret = select(fd + 1, NULL, &ww_set, NULL, &tv)) <0)
	{
		return -1;
	}
	if (FD_ISSET(fd, &ww_set))
	{      
		return write(fd, buf, size);
	}
	return -1;
}

static INT NetSendPacket(INT fd, void *buf, INT	len)
{  
	int	            writeByte = 0;

	if (buf ==NULL)	return -1;
	if (len <= 0)	return  0;
	if (len != SIZEOFNETMSGPACK)	len = SIZEOFNETMSGPACK;
	writeByte = NetSendPacketVa(fd, buf, SIZEOFNETMSGPACK, TIMEOUT_SEC, TIMEOUT_USEC);
	return	writeByte;
}

static VOID NetMakePacket(NETMSGPACKET	*sp, ULONG	msg_type, ULONG	sub_type,INT len, ULONG err_code)
{
	if (sp == NULL)
		return;
	sp->MsgHead.sync = __start_code__;
	sp->MsgHead.msgType = msg_type;
	sp->MsgHead.len = len - SIZEOFNETMSGHEAD;
	sp->MsgHead.errCode = err_code;
	sp->MsgHead.subType	= sub_type;
	return;
}

int DaemonUpgradeNotifyFinish(void)
{
    DaemonUpgradeContext *ctx = daemon_upgrade_GetCtx();

    if (ctx->bUpgrading) {
        NetMakePacket(&ctx->sp, MSG_UPDATE_RESP, 0, 0, 0);
        ctx->sp.MsgHead.reserve = 86;
        NetSendPacket(ctx->fd, &ctx->sp, SIZEOFNETMSGPACK);
        IPCAM_DEBUG("Send signal 101  1");
        
        NetMakePacket(&ctx->sp, MSG_UPDATE_RESP, 0, 0, 0);
        ctx->sp.MsgHead.reserve = 101;
        NetSendPacket(ctx->fd, &ctx->sp, SIZEOFNETMSGPACK);
        IPCAM_DEBUG("Send signal 101  2");

        NetMakePacket(&ctx->sp, MSG_UPDATE_RESP, 0, 0, 0);
        ctx->sp.MsgHead.reserve = 101;
        NetSendPacket(ctx->fd, &ctx->sp, SIZEOFNETMSGPACK);
        IPCAM_DEBUG("Send signal 101  2");
        
        NetMakePacket(&ctx->sp, MSG_UPDATE_RESP, 0, 0, 0);
        ctx->sp.MsgHead.reserve = 101;
        NetSendPacket(ctx->fd, &ctx->sp, SIZEOFNETMSGPACK);
        IPCAM_DEBUG("Send signal 101  3");
    }

    return 0;
}

static BOOL UpdateFile(INT Fd)
{
	INT 			nErrCnt		  = 0;
	INT				nCnt		  = 0;
	INT 			nFileLen      = 0;
	INT				iRet		  = 0;
	INT 			wRet		  = 0;
	CHAR			szBuf[4096]	  = {0};
	CHAR			szCmd[256]	  = {0};
	CHAR            FileName[128] = {0};
	FILE*			pFile		  = NULL;
	CHAR            NewVer[128]   = {0};
	CHAR			TmpVer[128]	  = {0};
	DIR            *pDir          = NULL;
	struct dirent  *pDirent       = NULL;
	NETMSGPACKET	sp;

	struct timeval  wTimeOut;
	fd_set			FdSet;
	struct timeval  temptime;
	wTimeOut.tv_sec  = 3;
	wTimeOut.tv_usec = 1000;
	FD_ZERO(&FdSet);
	FD_SET(Fd, &FdSet);


    if(0 >= (iRet = select(Fd + 1, &FdSet, 0, 0, &wTimeOut))){
        return FALSE;
    }
	memset(&sp, 0, sizeof(sp));
	if( (iRet = recv(Fd, &sp, sizeof(sp), 0)) <= 0 )
	{
		perror("recv ::");
		return FALSE;
	}
	if( sp.MsgHead.sync != __start_code__ || iRet != sizeof(sp)
		|| sp.MsgHead.msgType != MSG_UPDATE_REQ){
				IPCAM_DEBUG("recv MSG_UPDATE_REQ OKOK");
				return FALSE;
	}
	gettimeofday(&temptime, NULL);
	IPCAM_DEBUG("recv MSG_UPDATE_REQ time = %ld, %ld", temptime.tv_sec, temptime.tv_usec);
    

	nFileLen = sp.MsgDevUpdate.DevUpdate.iFileLen;
//	IPCAM_DEBUG("mark ");

	IPCAM_DEBUG("nFileLen:%d,nFileType:%d",nFileLen,sp.MsgDevUpdate.DevUpdate.nFileType);
	switch (sp.MsgDevUpdate.DevUpdate.nFileType){
		case UPDATE_TYPE_PTZ:
			if (NULL == (pDir=opendir(PATH_PTZ_FILE))){
				memset(szCmd, 0, sizeof(szCmd));
				sprintf(szCmd, "mkdir -p %s", PATH_PTZ_FILE);
				IPCAM_DEBUG("%s", szCmd);
				hi_system(szCmd);
			}else{
				closedir(pDir);
				pDir=NULL;
			}
			//创建完目录后构造文件名
			memset(FileName, 0, sizeof(FileName));
			sprintf(FileName,"%s/%s",PATH_PTZ_FILE, sp.MsgDevUpdate.DevUpdate.szUpdateFileName);
			IPCAM_DEBUG("file name :%s\t size :%d!", sp.MsgDevUpdate.DevUpdate.szUpdateFileName, sp.MsgDevUpdate.DevUpdate.iFileLen);
			break;
		case UPDATE_TYPE_APP:
			#ifdef NVR_3520D
			sprintf(FileName, "%s/%s", PATH_UPGRADE_DIR_APP, sp.MsgDevUpdate.DevUpdate.szUpdateFileName);
			#else   //nvr 获得传输的文件名称
			///App  UPGRADE_TYPE_APP = "app" 更新包是不是以"app"开头，否则更新的文件错误；
			memset(szCmd,0,256);
			sprintf(szCmd, "rm -rf %s", PATH_UPGRADE_DIR_APP);
			hi_system(szCmd);
			memset(szCmd,0,256);
			sprintf(szCmd, "mkdir -p %s", PATH_UPGRADE_DIR_APP);
			hi_system(szCmd);
			if (NULL == (pDir=opendir(PATH_UPGRADE_DIR_APP))){//版本直接不存在，连目录都没有
				memset(szCmd, 0, sizeof(szCmd));
				sprintf(szCmd, "mkdir -p %s", PATH_UPGRADE_DIR_APP);
				hi_system(szCmd);
				IPCAM_DEBUG("%s",szCmd);
			}
			else{
				bzero(NewVer, sizeof(NewVer));
				while (NULL != (pDirent=readdir(pDir)))	{
					if (NULL != strstr(pDirent->d_name, UPGRADE_TYPE_APP)){
						break;
					}		
				}
			}

			if (0 == strlen(NewVer)){
				if(NULL != pDir)  closedir(pDir);
				memset(FileName, 0, sizeof(FileName));
				sprintf(FileName, "%s/%s", PATH_UPGRADE_DIR_APP, sp.MsgDevUpdate.DevUpdate.szUpdateFileName);
				//空目录就必须构建目录和文件名；
			} else {
				strcpy(TmpVer, NewVer);//现在TmpVer中的是拷贝原来版本的文件名，接下来开始比较版本
				strcpy(NewVer, CompareVer(sp.MsgDevUpdate.DevUpdate.szUpdateFileName, NewVer));
				//现在NewVer中是网络升级包中的版本文件名
				IPCAM_DEBUG("TmpVer[%s] NewVer[%s]", TmpVer, NewVer);
				//发现有更新的文件
				if(NULL != pDir)  closedir(pDir);
				memset(FileName, 0, sizeof(FileName));
				//重新配置新的文件名和目录
				sprintf(FileName, "%s/%s", PATH_UPGRADE_DIR_APP, sp.MsgDevUpdate.DevUpdate.szUpdateFileName);		
			}
#ifdef __HuaweiLite__
			int pktSize = 0;
			char tmpFileName[128] = "";
			snprintf(tmpFileName, sizeof(FileName), "%s", FileName);
			memset(FileName, 0, sizeof(FileName));
			sprintf(FileName, "%s/%s", PATH_UPGRADE_DIR_APP, strstr(tmpFileName, "V"));	

			pktSize = (sp.MsgDevUpdate.DevUpdate.iFileLen + 0x10000 - 1) / 0x10000;
			pktSize *= 0x10000;
            iRet = UpgradeInit(pktSize);
            if (iRet < 0) {
                return FALSE;
            }
#endif /* __HuaweiLite__ */

			#endif
			break;
		default:
			return FALSE;
	}

	
	NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
	NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);

	gettimeofday(&temptime, NULL);

	IPCAM_DEBUG("mark ");

	if (NULL == (pFile=fopen(FileName, "w"))){
		IPCAM_DEBUG("create file [%s] error!", FileName);
		return FALSE;
	}
	FD_ZERO(&FdSet);
	FD_SET(Fd, &FdSet);

	nErrCnt = 0;
	while(nCnt<nFileLen)
	{
		wTimeOut.tv_sec  = 3L;
		wTimeOut.tv_usec = 1000L;

		if ( 0>= (iRet=select(Fd+1,&FdSet,NULL,NULL,&wTimeOut))){
			perror("select:");
			if (nErrCnt++ > 10){
				IPCAM_DEBUG("send file break off or too slow");
				goto UPGRADE_ERROR_EXIT;
			}
			continue;
		}
		if (FD_ISSET(Fd, &FdSet)){	
			memset(szBuf, 0, sizeof(szBuf));
			if (0>=(iRet=recv(Fd, szBuf, sizeof(szBuf), 0))){
				IPCAM_DEBUG("mark ");
				goto UPGRADE_ERROR_EXIT;
			}	
		}
		//将接收的包放到创建的新目录中
		wRet = fwrite(szBuf, 1, iRet, pFile);
		if(wRet != iRet)
		{
			IPCAM_DEBUG("mark ");
			goto UPGRADE_ERROR_EXIT;
		}
		nCnt += wRet;//保证接多少写多少
	}
	fclose(pFile);
	pFile = NULL;
	
	NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
	sp.MsgHead.reserve = 10;
	NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);

	if (NULL != strstr(FileName, "V"))
	{			
		memset(szCmd, 0, sizeof(szCmd));

#ifdef BATTERY_PRODUCT
		NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
		sp.MsgHead.reserve = 20;
		NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);

		NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
		sp.MsgHead.reserve = 70;
		NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
		IPCAM_DEBUG("Send signal 70");
		
        sprintf(szCmd, "/usr/bin/update.sh %s &", FileName);
 		IPCAM_DEBUG(szCmd);
        //hi_system(szCmd);
        system(szCmd);
                
		/* 让搜索工具等待升级成功, 进度维持在70%, update.sh升级成功后会创建/tmp/update_success */
		while (1) {
            if (access("/tmp/update_success", F_OK) == 0)
            {
        		NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
        		sp.MsgHead.reserve = 101;
        		NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
        		IPCAM_DEBUG("Send signal 101  1");
        		NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
        		sp.MsgHead.reserve = 101;
        		NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
        		IPCAM_DEBUG("Send signal 101  2");
        	
        		NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
        		sp.MsgHead.reserve = 101;
        		NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
        		IPCAM_DEBUG("Send signal 101  3");
        		sleep(10); //等待update.sh脚本自己重启系统
        		break;
            }
            else if (access("/tmp/update_fail", F_OK) == 0)
            {
                goto UPGRADE_ERROR_EXIT;
            }
            else
            {
                sleep(1);
            }
		}

#elif __HuaweiLite__
	NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
	sp.MsgHead.reserve = 20;
	NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
	IPCAM_DEBUG(szCmd);

	NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
	sp.MsgHead.reserve = 70;
	NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
	IPCAM_DEBUG("Send signal 70");

    DaemonUpgradeContext *ctx = daemon_upgrade_GetCtx();
    ctx->bUpgrading = 1;
    memcpy(&ctx->sp, &sp, sizeof(sp));
    ctx->fd = Fd;
    
	//update
	UpgradeRun(FileName);
	
	NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
	sp.MsgHead.reserve = 101;
	NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
	IPCAM_DEBUG("Send signal 101  1");

	NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
	sp.MsgHead.reserve = 101;
	NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
	IPCAM_DEBUG("Send signal 101  2");
	
	NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
	sp.MsgHead.reserve = 101;
	NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
	IPCAM_DEBUG("Send signal 101  3");

    usleep(200 * 1000);
	UpgradeDeinit();
	
	SystemReboot("upgrade success by daemon");	
#else
		sprintf(szCmd, "tar -xvf %s -C %s", FileName, PATH_APP);
		NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
		sp.MsgHead.reserve = 20;
		NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
		IPCAM_DEBUG(szCmd);
		hi_system(szCmd);

		NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
		sp.MsgHead.reserve = 70;
		NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
		
		IPCAM_DEBUG("Send signal 70");
		
		NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
		sp.MsgHead.reserve = 101;
		NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
		IPCAM_DEBUG("Send signal 101  1");
		NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
		sp.MsgHead.reserve = 101;
		NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
		IPCAM_DEBUG("Send signal 101  2");
		NetMakePacket(&sp, MSG_UPDATE_RESP, 0, 0, 0);
		sp.MsgHead.reserve = 101;
		NetSendPacket(Fd, &sp, SIZEOFNETMSGPACK);
		IPCAM_DEBUG("Send signal 101  3");
#endif
		fsync (Fd);
		sync();
		usleep(1000*1000);
		return TRUE;
	}

UPGRADE_ERROR_EXIT:
	if(pFile != NULL)	fclose(pFile);
	
#ifndef __HuaweiLite__
	memset(szCmd , 0 , sizeof(szCmd));
	sprintf(szCmd ,"rm -rf %s" , FileName);
	hi_system(szCmd);
#endif /* __HuaweiLite__ */	
	sync();
	return FALSE;
}

static VOID *UpGradeByNet_Pthread(VOID *args)
{
	INT  SockServer = -1;
	INT  SockClient = -1;
	INT  Enable     =  1;
	INT  privority  = -1;

	socklen_t  CAddrLen   	=  0;
	ULONG err_code  		=  ERR_NO_ERROR;
	CHAR pzRecBuff[2048] 	= {0};
	CHAR cmd[256] 			= {0};
	NETMSGPACKET * sp    	= (NETMSGPACKET *)pzRecBuff;
	LPTHREAD_ARG *parg   	= (LPTHREAD_ARG *)args;

	NETMSGPACKET str_pkt;
	struct sockaddr_in ClientAddr = {0};
	struct sockaddr_in ServerAddr = {0};
	struct timeval   TimeOut;
	fd_set           FdSet;

	memset(&str_pkt, 0, sizeof(str_pkt));
	IPCAM_PTHREAD_DETACH;
	signal(SIGPIPE, SIG_IGN);
	
#ifndef ETH_NET
	while(FALSE == parg->wifistatu || 0 > (SockServer=socket(AF_INET,SOCK_STREAM,0)))
	{	
		//IPCAM_DEBUG("Socket create faile!");
		sleep(2);
	}
#else
	if (0 > (SockServer=socket(AF_INET,SOCK_STREAM,0)))
	{
		IPCAM_DEBUG("Socket create faile!");
		return (void *)-1;
	}
#endif
	//fcntl(SockServer,F_SETFL,O_NONBLOCK); //设置套接字为非阻塞
	Enable = 1;

	if(0 > setsockopt(SockServer,SOL_SOCKET,SO_REUSEADDR,(const char*)&Enable,sizeof(int)))
	{
		perror("setsockopt:: SO_REUSEADDR:");
	}


	bzero(&ServerAddr,sizeof(ServerAddr));
	ServerAddr.sin_family        = AF_INET;
	ServerAddr.sin_port          = htons(PORT_UPDATE_FILE);
	ServerAddr.sin_addr.s_addr   = htonl(INADDR_ANY);
	
	if (0 > (bind(SockServer, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr))))
	{
		perror("bind::");
		IPCAM_DEBUG("bind faile!");
		goto UPGRADEBYNET_EXIT;		
	}
	
	listen(SockServer, 5);
	
	while(TRUE)
	{
		CAddrLen = sizeof(ClientAddr);
		if (0 > (SockClient = accept(SockServer,(struct sockaddr*)&ClientAddr,&CAddrLen)))
		{
			IPCAM_DEBUG("Accept faile!");
			goto UPGRADEBYNET_EXIT;
		}
		IPCAM_DEBUG("Link Success!ip=%s,port=%d,len=%d", inet_ntoa(ClientAddr.sin_addr),ntohs(ClientAddr.sin_port),CAddrLen);

		TimeOut.tv_sec  = 2;
		TimeOut.tv_usec = 1000;
		FD_ZERO(&FdSet);
		FD_SET(SockClient, &FdSet);
		if(0>=select(SockClient+1, &FdSet, 0, 0, &TimeOut))
		{
			usleep(1000 * 100);
			err_code = ERR_UNKNOW;
			continue;
		}

		recv(SockClient, (NETMSGPACKET *)sp, SIZEOFNETMSGPACK, 0);
		if ((__start_code__ == sp->MsgHead.sync) &&
			(MSG_CONNECT_UPDATE == sp->MsgHead.msgType))
		{
        	{
		    	IPCAM_DEBUG("Recv Upgrade packet Nowing,And Net get sem!");
				NetMakePacket(&str_pkt, MSG_USERLOGIN_RESP, privority, 0, 1);
				NetSendPacket(SockClient, &str_pkt, SIZEOFNETMSGPACK);

#ifndef __HuaweiLite__
				usleep(200*1000);
				
                if(0 != hi_system("killall ipcam")) //杀死应用程序
					rt_system("killall ipcam");
				Upgrade_now = 1;//升级标志,防止看门狗重启 fyj

#ifndef BATTERY_PRODUCT
				#ifdef PLATFORM_jz_t20
				sleep(3);
                if (WatchdogDestory() < 0) {
                    sleep(2);
                    WatchdogDestory();
                }
                #else
                sleep(1);
                #endif
#endif                
#endif /* __HuaweiLite__ */

				if (FALSE == UpdateFile(SockClient)){
					IPCAM_DEBUG("Update fail!");	
					Upgrade_now = 0;					
					err_code = ERR_NO_ERROR;
					NetMakePacket(&str_pkt, MSG_UPDATE_RESP, privority, 0, -1);
					NetSendPacket(SockClient, &str_pkt, SIZEOFNETMSGPACK);	
				}else{

#ifndef __HuaweiLite__
					//2.3后的版本升回2.3及之前版本，该文件会导致死机
					snprintf(cmd,sizeof(cmd),"rm -f %s/video/timer/*.cache",TARGET_DIR);
					rt_system(cmd);
					snprintf(cmd,sizeof(cmd),"rm -f /root/video/timer/*.cache");
					rt_system(cmd);				
					sleep(3);
					sync();
					system("reboot");
					sleep(5);
				    system("reboot -f");
#endif /* __HuaweiLite__ */				    
					pthread_exit(NULL);
				}	
			}
		}
		else if((0xE0CF == sp->MsgHead.sync))
		{
#ifdef __HuaweiLite__
            char ip[32] = "";
            int argc = 8;
            snprintf(ip, sizeof(ip), "%s", inet_ntoa(ClientAddr.sin_addr));
            char *argv[] = {"-c",ip,"-P","1","-i","1","-t","15"};
            NetIperf(argc, argv);
#else
			//_printd(">MsgHead.sync:%x,,,MsgHead.msgType:%x\n", sp->MsgHead.sync,sp->MsgHead.msgType);
			memset(pzRecBuff,0,sizeof(pzRecBuff));
			
			sprintf(pzRecBuff,"/app/bin/iperf -c %s -P 1 -i 1 -p 5001 -f k -t 15",inet_ntoa(ClientAddr.sin_addr));
			_printd("%s\n",pzRecBuff);
			system(pzRecBuff);
#endif /* __HuaweiLite__ */					
			close(SockClient);
			continue;
		}
	}
//UPGRADEBYNET_ERR:
	NetMakePacket(&str_pkt, MSG_UPDATE_RESP, privority, 0, err_code);
	NetSendPacket(SockClient, &str_pkt, SIZEOFNETMSGPACK);
	close(SockClient);

UPGRADEBYNET_EXIT:
	shutdown(SockClient, 2);
	close(SockServer);
	return (void *)-1;
}

BOOL Daemon_StartUpGradeByNet(LPTHREAD_ARG* arg)
{
	INT iRet = FALSE;
	IPCAM_CREATE_THREADEX(UpGradeByNet_Pthread, arg, iRet);
	return iRet;
}
#endif

